/****************************************************************************
 * Copyright (C) 2025 Chenyz. All rights reserved.
 *
 * @file    TinyOS_MailBox.c
 *
 * @par     dependencies
 *          - TinyOS_MailBox.h (Mailbox management definitions)
 *          - TinyOS_Event.h (Event management definitions)
 *          - TinyOS_Task.h (Task management definitions)
 *          - TinyOS_Objects.h (Core data structures)
 *
 * @author  Chenyz
 *
 * @brief   Mailbox management module for TinyOS with following features:
 *          - FIFO and priority-based message queuing
 *          - Task blocking and waking on mailbox operations
 *          - Timeout support for message reception
 *          - Non-blocking message send/receive options
 *          - Circular buffer implementation for message storage
 *          - Critical section protection for thread-safe operations
 *          - Mailbox flushing and deletion with task notification
 *          - Integration with event and task management systems
 *          - Cross-platform compatibility (bare-metal/RTOS systems)
 *
 * @version V1.0
 * @date    2025-05-23
 *
 * @note    Coding standard:
 *          - 4 spaces per indent level
 *          - Follow MISRA-C 2012 guidelines
 *          - Compiler compatibility: C99 and above
 *
 ****************************************************************************/

#include "TinyOS_MailBox.h"
#include "TinyOS_Event.h"
#include "TinyOS_Task.h"
#include "TinyOS_Objects.h"


#if TINYOS_ENABLE_MAILBOX == 1

/**
 * @brief Initializes a mailbox with specified parameters
 * 
 * This function sets up a mailbox control block with the specified message
 * buffer and maximum message count. The mailbox uses a circular buffer for
 * message storage and is integrated with the event system for task synchronization.
 * 
 * @param MailBox Pointer to the mailbox structure to be initialized
 * @param MsgBuffer Pointer to the message buffer array
 * @param MaxCount Maximum number of messages the mailbox can hold
 */
void TinyOS_MailBoxInit(
    TinyOS_MailBoxType* MailBox,
    void** MsgBuffer,
    uint32_t MaxCount
)
{
    /* Initialize the event block for mailbox operations */
    TinyOS_EventBlockInit(&(MailBox->EventBlock), TinyOS_EventTypeMailBox);
    MailBox->MaxCount = MaxCount;
    MailBox->MsgBuffer = MsgBuffer;
    MailBox->MailCount = 0;
    MailBox->WriteIndex = 0;
    MailBox->ReadIndex = 0;
}

/**
 * @brief Receives a message from the mailbox with optional timeout
 * 
 * This function attempts to receive a message from the mailbox. If messages
 * are available, it returns immediately with the message. If no messages are
 * available, the task will block until a message arrives or the timeout expires.
 * 
 * @param MailBox Pointer to the mailbox structure
 * @param Msg Pointer to store the received message
 * @param WaitTicks Maximum time to wait for a message (0 = no waiting)
 * @return uint32_t Error code indicating operation result
 */
uint32_t TinyOS_MailBoxTake(
    TinyOS_MailBoxType* MailBox,
    void** Msg,
    uint32_t WaitTicks
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();  
    
    /* Check if messages are available in the mailbox */
    if(MailBox->MailCount > 0)
    {
        /* Message available - retrieve from circular buffer */
        MailBox->MailCount--;
        *Msg = MailBox->MsgBuffer[MailBox->ReadIndex];
        MailBox->ReadIndex++;
        
        /* Wrap around read index if necessary */
        if(MailBox->ReadIndex >= MailBox->MaxCount)
        {
            MailBox->ReadIndex = 0;
        }
        
        TinyOS_TaskExitCritical(Stauts);  
        return TinyOS_ErrorType_NoError;    
    }
    else
    {
        /* No messages available - put task into waiting state */
        TinyOS_EventWait(
            &(MailBox->EventBlock), 
            CurrentTask, 
            (void*)0, 
            TinyOS_EventTypeMailBox, 
            WaitTicks
        );
            
        TinyOS_TaskExitCritical(Stauts); 
            
        /* Schedule another task while waiting */
        TinyOS_TaskScheduler();
        
        /* Retrieve message and result after being woken */
        *Msg = CurrentTask->TaskEventMsg;
        return CurrentTask->TaskEventWaitResult;      
    }              
}

/**
 * @brief Receives a message from the mailbox without blocking
 * 
 * This function attempts to receive a message from the mailbox without blocking
 * the calling task. If a message is available, it is returned immediately.
 * If not, the function returns an error without waiting.
 * 
 * @param MailBox Pointer to the mailbox structure
 * @param Msg Pointer to store the received message
 * @return uint32_t Error code indicating operation result
 */
uint32_t TinyOS_MailBoxTakeNoWait(
    TinyOS_MailBoxType* MailBox,
    void** Msg
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();  
    
    /* Check if messages are available in the mailbox */
    if(MailBox->MailCount > 0)
    {
        /* Message available - retrieve from circular buffer */
        MailBox->MailCount--;
        *Msg = MailBox->MsgBuffer[MailBox->ReadIndex];
        MailBox->ReadIndex++;
        
        /* Wrap around read index if necessary */
        if(MailBox->ReadIndex >= MailBox->MaxCount)
        {
            MailBox->ReadIndex = 0;
        }
        
        TinyOS_TaskExitCritical(Stauts);  
        return TinyOS_ErrorType_NoError;   
    }
    else
    {
        /* No messages available - return error without blocking */
        TinyOS_TaskExitCritical(Stauts);  
        return TinyOS_ErrorType_SourceUnavailable; 
    }      
}

/**
 * @brief Sends a message to the mailbox
 * 
 * This function sends a message to the mailbox. If tasks are waiting for messages,
 * the highest priority task is woken and receives the message directly. If no
 * tasks are waiting, the message is stored in the mailbox buffer.
 * 
 * @param MailBox Pointer to the mailbox structure
 * @param Msg Message to be sent
 * @param MailPriority Priority flags for message sending (e.g., front of queue)
 * @return uint32_t Error code indicating operation result
 */
uint32_t TinyOS_MailBoxGive(    
    TinyOS_MailBoxType* MailBox,
    void* Msg,
    uint32_t MailPriority
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();
    
    /* Check if any tasks are waiting for messages */
    if(TinyOS_EventWaitCount(&(MailBox->EventBlock)) > 0)
    {
        /* Wake the highest priority waiting task and deliver message directly */
        TinyOS_TaskType* TempTaskHandler = TinyOS_EventWake(       
            &(MailBox->EventBlock), 
            Msg, 
            TinyOS_ErrorType_NoError
        );
        
        /* Schedule immediately if woken task has higher priority */
        if(TempTaskHandler->TaskPrioity > CurrentTask->TaskPrioity)
        {         
            TinyOS_TaskScheduler();
        }
    }
    else
    {
        /* No tasks waiting - store message in mailbox buffer */
        if(MailBox->MailCount >= MailBox->MaxCount)
        {
            /* Mailbox is full - return error */
            TinyOS_TaskExitCritical(Stauts);
            return TinyOS_ErrorType_SourceFull;
        }
        else
        {
            /* Store message based on priority flag */
            if(MailPriority & TINYOS_MAILBOX_SEND_FRONT)
            {
                /* Insert at front of queue (high priority message) */
                if(MailBox->ReadIndex == 0)
                {
                    MailBox->ReadIndex = MailBox->MaxCount - 1;
                }
                else
                {
                    MailBox->ReadIndex--;
                }
                MailBox->MsgBuffer[MailBox->ReadIndex] = Msg;
            }
            else
            {
                /* Insert at back of queue (normal priority message) */
                MailBox->MsgBuffer[MailBox->WriteIndex] = Msg;
                MailBox->WriteIndex++;
                
                /* Wrap around write index if necessary */
                if(MailBox->WriteIndex >= MailBox->MaxCount)
                {
                    MailBox->WriteIndex = 0;
                }           
            }
            
            /* Increment message count */
            MailBox->MailCount++;
        }
    }          
    
    TinyOS_TaskExitCritical(Stauts);
    return TinyOS_ErrorType_NoError;
}

/**
 * @brief Flushes all messages from the mailbox
 * 
 * This function clears all messages from the mailbox buffer. If tasks are
 * waiting for messages, the flush operation is not performed.
 * 
 * @param MailBox Pointer to the mailbox structure
 */
void TinyOS_MailBoxFlush(TinyOS_MailBoxType* MailBox)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();
    
    /* Only flush if no tasks are waiting for messages */
    if(TinyOS_EventWaitCount(&(MailBox->EventBlock)) == 0)
    {
        MailBox->MailCount = 0;
        MailBox->ReadIndex = 0;
        MailBox->WriteIndex = 0;
    }  
    
    TinyOS_TaskExitCritical(Stauts); 
}

/**
 * @brief Deletes the mailbox and notifies all waiting tasks
 * 
 * This function removes the mailbox from the system, waking up all tasks
 * that were waiting for messages with a deletion notification.
 * 
 * @param MailBox Pointer to the mailbox structure to be deleted
 * @return uint32_t Number of tasks that were waiting on the mailbox
 */
uint32_t TinyOS_MailBoxDeleteWait(TinyOS_MailBoxType* MailBox)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();

    /* Wake all tasks waiting on this mailbox with deletion notification */
    uint32_t DeleteCount = TinyOS_EventRemoveAll(
        &(MailBox->EventBlock), 
        (void*)0, 
        TINYOS_TASK_DELETED
    );
    
    TinyOS_TaskExitCritical(Stauts);
        
    /* Schedule tasks if any were woken */
    if(DeleteCount > 0)
    {
        TinyOS_TaskScheduler();
    }
    
    return DeleteCount;
}     

/**
 * @brief Retrieves information about a mailbox
 * 
 * This function returns the current state of the mailbox including its
 * message count, maximum capacity, and number of tasks waiting for messages.
 * 
 * @param MailBox Pointer to the mailbox structure
 * @param Info Pointer to a structure where the mailbox information will be stored
 */
void TinyOS_MailBoxGetInfo(
    TinyOS_MailBoxType* MailBox,
    TinyOS_MailBoxInfo* Info
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();    

    /* Copy mailbox state information */
    Info->MailCount = MailBox->MailCount;
    Info->MailBoxMaxCount = MailBox->MaxCount;
    Info->TaskCount = TinyOS_EventWaitCount(&(MailBox->EventBlock));

    TinyOS_TaskExitCritical(Stauts);    
}


#endif

